package com.zhg.shortlink.service;

import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 分层布隆过滤器（支持Stream同步）
 * @author 朱洪刚
 * @version 1.0
 * @data 2025/10/21 09:22
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class TieredBloomFilterService {
    private final TimeBasedBloomFilterService timeBasedBloomFilter;
    private final RedisTimeBasedBloomFilterService redisTimeBasedBloomFilter; // 新增
    private final BloomFilterStreamService streamService;

    // 废弃传统布隆过滤器
    // private final LocalBloomFilterService localBloomFilter; // 删除
    // private final RedisBloomFilterService redisBloomFilter; // 删除


    /**
     * 分层检查：先本地，再Redis
     */
    public boolean mightContain(String shortCode) {
        // 第一层：本地时间分片布隆过滤器（最新数据，零延迟）
        if (timeBasedBloomFilter.mightContain(shortCode)) {
            return true;
        }

        // 第二层：Redis时间分片布隆过滤器（全局共享，兜底）
        return redisTimeBasedBloomFilter.mightContain(shortCode);
    }

    /**
     * 添加到时间分片布隆过滤器
     */
    public void put(String shortCode) {
        if (shortCode == null || shortCode.trim().isEmpty()) {
            log.warn("shortCode为空或null");
            return;
        }

        try {
            // 1. 添加到本地时间分片
            timeBasedBloomFilter.add(shortCode);

            // 2. 添加到Redis时间分片
            redisTimeBasedBloomFilter.add(shortCode);

            // 3. 发布到Stream同步到其他节点
            streamService.publishNewShortCode(shortCode);

            log.debug("时间分片布隆过滤器添加成功: {}", shortCode);
        } catch (Exception e) {
            log.error("时间分片布隆过滤器添加失败: shortCode={}", shortCode, e);
        }
    }

    /**
     * 批量添加
     */
    public void addBatch(List<String> shortCodes) {
        for (String shortCode : shortCodes) {
            put(shortCode);
        }
    }

    /**
     * 获取统计信息
     */
    public String getStats() {
        return String.format("时间分片架构统计 - 本地: [%s], Redis: [%s]",
                timeBasedBloomFilter.getStats(),
                redisTimeBasedBloomFilter.getStats());
    }

    /**
     * 获取节点信息
     * 包含节点ID、服务状态、统计信息等
     */
    public NodeInfo getNodeInfo() {
        try {
            // 获取节点ID（通过RedisTimeBasedBloomFilterService）
            String nodeId = getNodeId();

            // 获取服务状态
            boolean localServiceActive = timeBasedBloomFilter != null;
            boolean redisServiceActive = redisTimeBasedBloomFilter != null;
            boolean streamServiceActive = streamService != null;

            // 获取统计信息
            String localStats = localServiceActive ? timeBasedBloomFilter.getStats() : "服务未激活";
            String redisStats = redisServiceActive ? redisTimeBasedBloomFilter.getStats() : "服务未激活";

            // 获取系统信息
            Runtime runtime = Runtime.getRuntime();
            long totalMemory = runtime.totalMemory();
            long freeMemory = runtime.freeMemory();
            long usedMemory = totalMemory - freeMemory;
            long maxMemory = runtime.maxMemory();

            return NodeInfo.builder()
                    .nodeId(nodeId)
                    .timestamp(System.currentTimeMillis())
                    .localServiceActive(localServiceActive)
                    .redisServiceActive(redisServiceActive)
                    .streamServiceActive(streamServiceActive)
                    .localStats(localStats)
                    .redisStats(redisStats)
                    .memoryUsedMB(usedMemory / 1024 / 1024)
                    .memoryTotalMB(totalMemory / 1024 / 1024)
                    .memoryMaxMB(maxMemory / 1024 / 1024)
                    .memoryUsagePercent((double) usedMemory / maxMemory * 100)
                    .build();

        } catch (Exception e) {
            log.error("获取节点信息失败", e);
            return NodeInfo.builder()
                    .nodeId("unknown")
                    .timestamp(System.currentTimeMillis())
                    .localServiceActive(false)
                    .redisServiceActive(false)
                    .streamServiceActive(false)
                    .localStats("获取失败: " + e.getMessage())
                    .redisStats("获取失败: " + e.getMessage())
                    .memoryUsedMB(0L)
                    .memoryTotalMB(0L)
                    .memoryMaxMB(0L)
                    .memoryUsagePercent(0.0)
                    .build();
        }
    }

    /**
     * 获取节点ID（委托给RedisTimeBasedBloomFilterService）
     */
    private String getNodeId() {
        try {
            // 通过反射调用RedisTimeBasedBloomFilterService的getNodeId方法
            java.lang.reflect.Method getNodeIdMethod = redisTimeBasedBloomFilter.getClass().getDeclaredMethod("getNodeId");
            getNodeIdMethod.setAccessible(true);
            return (String) getNodeIdMethod.invoke(redisTimeBasedBloomFilter);
        } catch (Exception e) {
            log.warn("无法获取节点ID，使用默认值", e);
            return "node-" + System.currentTimeMillis() % 10000;
        }
    }

    /**
     * 节点信息数据类
     */
    public static class NodeInfo {
        private String nodeId;
        private long timestamp;
        private boolean localServiceActive;
        private boolean redisServiceActive;
        private boolean streamServiceActive;
        private String localStats;
        private String redisStats;
        private long memoryUsedMB;
        private long memoryTotalMB;
        private long memoryMaxMB;
        private double memoryUsagePercent;

        // 私有构造函数
        private NodeInfo() {}

        // Builder模式
        public static Builder builder() {
            return new Builder();
        }

        public static class Builder {
            private NodeInfo nodeInfo = new NodeInfo();

            public Builder nodeId(String nodeId) {
                nodeInfo.nodeId = nodeId;
                return this;
            }

            public Builder timestamp(long timestamp) {
                nodeInfo.timestamp = timestamp;
                return this;
            }

            public Builder localServiceActive(boolean localServiceActive) {
                nodeInfo.localServiceActive = localServiceActive;
                return this;
            }

            public Builder redisServiceActive(boolean redisServiceActive) {
                nodeInfo.redisServiceActive = redisServiceActive;
                return this;
            }

            public Builder streamServiceActive(boolean streamServiceActive) {
                nodeInfo.streamServiceActive = streamServiceActive;
                return this;
            }

            public Builder localStats(String localStats) {
                nodeInfo.localStats = localStats;
                return this;
            }

            public Builder redisStats(String redisStats) {
                nodeInfo.redisStats = redisStats;
                return this;
            }

            public Builder memoryUsedMB(long memoryUsedMB) {
                nodeInfo.memoryUsedMB = memoryUsedMB;
                return this;
            }

            public Builder memoryTotalMB(long memoryTotalMB) {
                nodeInfo.memoryTotalMB = memoryTotalMB;
                return this;
            }

            public Builder memoryMaxMB(long memoryMaxMB) {
                nodeInfo.memoryMaxMB = memoryMaxMB;
                return this;
            }

            public Builder memoryUsagePercent(double memoryUsagePercent) {
                nodeInfo.memoryUsagePercent = memoryUsagePercent;
                return this;
            }

            public NodeInfo build() {
                return nodeInfo;
            }
        }

        // Getter方法
        public String getNodeId() { return nodeId; }
        public long getTimestamp() { return timestamp; }
        public boolean isLocalServiceActive() { return localServiceActive; }
        public boolean isRedisServiceActive() { return redisServiceActive; }
        public boolean isStreamServiceActive() { return streamServiceActive; }
        public String getLocalStats() { return localStats; }
        public String getRedisStats() { return redisStats; }
        public long getMemoryUsedMB() { return memoryUsedMB; }
        public long getMemoryTotalMB() { return memoryTotalMB; }
        public long getMemoryMaxMB() { return memoryMaxMB; }
        public double getMemoryUsagePercent() { return memoryUsagePercent; }

        @Override
        public String toString() {
            return String.format(
                    "NodeInfo{nodeId='%s', timestamp=%d, services=[local=%s, redis=%s, stream=%s], " +
                            "memory=[used=%dMB, total=%dMB, max=%dMB, usage=%.2f%%], " +
                            "localStats='%s', redisStats='%s'}",
                    nodeId, timestamp, localServiceActive, redisServiceActive, streamServiceActive,
                    memoryUsedMB, memoryTotalMB, memoryMaxMB, memoryUsagePercent,
                    localStats, redisStats
            );
        }
    }
}
